/**
 * @file
 *
 * @brief Logging support for Network Simulation Frameworks.
 *
 * @version 1.0
 * @author  Wei Tang <gauchyler@uestc.edu.cn>
 * @date    2015-02-26
 *
 * @copyright Copyright (c) 2015.
 *            National Key Laboratory of Science and Technology on Communications,
 *            University of Electronic Science and Technology of China.
 *            All rights reserved.
 */

#ifndef CONFIG_H__A5BE74BF_215D_493B_8BB1_8F90D9316F15
#define CONFIG_H__A5BE74BF_215D_493B_8BB1_8F90D9316F15


#include <nsfx/config.h>


////////////////////////////////////////////////////////////////////////////////
/**
 * @defgroup Log
 *
 * @brief Log support.
 *
 * # Motivation
 *
 * The log library is provided to ease the task of tracing a program.
 * The program outputs useful runtime information as log records that can be
 * stored and examined to analyze the program's behaviors.
 *
 * The log library aims to provide a set of log tools that are header-only,
 * easy-to-use, flexible, configurable, extensible and fast.
 *
 * The log facility in several existing network simulators are not flexible.
 * e.g., in NS3, the granularity of logging is a model/class (precisely,
 * a compilation unit).
 * i.e., it logs all events from all objects of the class, and it's hard to
 * monitor a single object of the class.
 * As a result, the amount log records is huge and hard to read, and must be
 * filtered for humans to find their focus.
 * It is not only efficient for analyzers, but also slows down the program.
 *
 * ## Configurability
 *
 * BOOST provides a log library.
 * In the library, compile-time functionals are adopted to make log filters.
 * It can be fast, but it does not provide runtime configurability directly.
 *
 * The log library in NSFX provides log filters in a modular way.
 * Each log filter is provided as a component that provides interface for
 * configurability.
 * Users can combine log filters to suit their specific needs.
 *
 * # Concept
 *
 * A *log source* generates runtime information as *log records*, and passes them
 * to *log sinks*.
 *
 * Log sources are the objects that generates log records.
 * The piece of program that generates log records is called a *log site*.
 *
 * A log record is a collection of *log values*.
 * Typical information includes human-readable message, severity level,
 * function name, file name, line number, object name, timestamp, etc.
 *
 * Log sinks are responsible to process the log records,
 * e.g., duplicate, modify, forward, format, display or store the log records.
 * A log sink is also called a *logger*.
 *
 * A log record may be passed and processed along a series of log sinks.
 * The log sources, log sinks and their connections generally form a directed
 * acylic graph.
 *
 * ## Log model
 *
 * In order to process log records, log sinks have to understand the types
 * and meanings of the named values generated by the log source.
 * Therefore, log sources and sinks are usually *coupled* that they **must** agree
 * upon the collection of named values in log records.
 *
 * The names and types of the log values are decided at design-time for
 * log sources and sinks, while log values and records are usually generated
 * by log sources at runtime.
 *
 * The library models the logging mechanism by event model.
 * The `ILogEvent` interface represents a log source.
 * The `ILogEventSink` interface represents a log sink.
 * The prototype of the event sink is `void Fire(LogRecord)`.
 *
 * An intermediate logger **shall** provide `ILogEvent` interface.
 * Thus, an intermediate logger can be regarded as a log source for
 * the downstream loggers.
 * A terminal logger does not have to provide `ILogEvent` interface.
 *
 * ## Log record
 *
 * The information to be logged is carried by log records.
 * A log record is an instance of the `LogRecord` class.
 * For performance considerations, `LogRecord` is defined as a common C++ class.
 * It is not a component class, since a component is too heavy, and it is not
 * neccesary for a log record to have the advanced functionalities such as
 * interface navigability.
 *
 * A log record is extensible to be able to carry arbitrary types of values.
 * i.e., the log values have to be type-erased.
 *
 * Extensibility and performance are usually contradictory.
 * Extensibility means the library has to use interfaces (virtual functions)
 * to hide the operation details implemented by users.
 *
 * A log operation can involve several virtual function calls, which can
 * be more expensive than the operation that generates a log record.
 *
 * ### Type erasure
 *
 * The type erasure can be implemented as union-based or interface-based.
 * However, union-based type erasure only supports a limited set of value types,
 * thus cannot provide sufficient extensibility.
 *
 * Interface-based type erasure has more overhead, since virtual functions are
 * used, but it is more extensible.
 *
 * ### Type dispatch
 *
 * There must be a way to recover the typed values carried by a log record.
 * The possible approaches include compile-time tag-based dispatch and runtime
 * index-based dispatch.
 *
 * The compile-time tag-based dispatch uses a set of predefined tags to identify
 * log values.
 * A log value is queried from a log record by using a tag.
 * The set of log values are determined at compile-time.
 * This approach is not easy-to-use.
 *
 * The runtime index-based dispatch uses a container to store the values.
 * The container can be associative to speed up lookup.
 * The index is usually a human-readible string.
 *
 * ## Log value
 *
 * A log record holds named values.
 * The values are held in a type-neutral way.
 * Each value is an instance of the `LogValue` class.
 * The class holds a pointer to the `ILogValue` interface.
 *
 * The `ILogValue` interface provides a single method `GetTypeId()` that gives
 * the type id of the stored value.
 * `ILogValue` is used to realize type-erasure.
 *
 * The `ITypedLogValue` class template is an interface that extends `ILogValue`,
 * and provides another method `ITypedLogValue::Get()` that returns
 * the stored value.
 *
 * A concrete log value class **must** implement `ITypedLogValue`.
 * `ITypedLogValue` is used to enable type-dispatcher.
 *
 * Users that implement `ITypedLogValue` **must** make sure that the underlying value
 * is kept available until log sinks access it.
 * However, the log sources may not always know when the underlying value will
 * be accessed by the log sinks.
 * e.g., it is not a problem in a single-threaded environment, the logger
 * will deliver log records to terminal log sinks immediately and wait for
 * them to complete.
 * However, in a multithreaded environment, the log sinks may reside in a
 * different thread and consumes the log records in a later time.
 * Therefore, attribute value **shall** store or refer to persistent values
 * whenever possible.
 *
 * The log library provides `MakeLogValue()` and `MakeConstantLogValue()` function
 * templates for making log values.
 *
 * `MakeLogValue()` stores a functor that returns a log value.
 * The functor **must** be valid until log sinks access it.
 * `MakeConstantLogValue()` stores a constant value.
 *
 * The `LogRecord` holds a shared object.
 * Thus, any modification of `LogRecord` is visible to all loggers.
 * To make a deep/separate copy of `LogRecord`, call its member function `Copy()`.
 *
 * ## Log macro
 *
 * The library provides several <i>log macros</i> to help the users to create
 * log records and commit them to a logger.
 *
 * @code{.cpp}
 * NSFX_LOG(logger) << "Some message.";
 * NSFX_LOG_LEVEL(logger, severity) << "Some message.";
 * NSFX_LOG_FATAL(logger) << "Some message.";
 * NSFX_LOG_ERROR(logger) << "Some message.";
 * NSFX_LOG_WARN(logger)  << "Some message.";
 * NSFX_LOG_INFO(logger)  << "Some message.";
 * NSFX_LOG_DEBUG(logger) << "Some message.";
 * NSFX_LOG_TRACE(logger) << "Some message.";
 * @endcode
 *
 * The log macros are acting as log sources, and the places where the macros
 * are used are log sites.
 *
 * The log macros are open for user-defined log sinks.
 *
 * Certain information must be provided at the log site.
 * e.g., message, severity level, function name, file name and line number.
 *
 * Other information can be argumented by the logger.
 * e.g., timestamp and scope.
 *
 * By default, the log macros provide the following named values:
 *
 * * `"LogMessage"`  : `const char*`
 * * `"LogSeverity"` : `LogSeverity`
 * * `"LogFunction"` : `const char*`
 * * `"LogFile"`     : `const char*`
 * * `"LogLine"`     : `uint32_t`
 *
 * The function name, file name and line number are not enabled by default.
 * Users have to define `NSFX_LOG_ENABLE_FUNCTION_NAME` macro to enable the
 * recording of function name, `NSFX_LOG_ENABLE_FILE_NAME` macro to enable
 * file name, and `NSFX_LOG_ENABLE_LINE_NUMBER` macro to enable line number.
 *
 * ## Log on-demand
 *
 * A component provides `ILogEvent` as a log source, and the log macros can
 * be used in the source code to create and commit log records.
 *
 * Sometimes, a log source is not interested.
 * It is expected that users do not have to change the source code (e.g.,
 * modify/remove the log sites) in order to disable logging.
 *
 * ### Discussions
 *
 * There are several schemes to accomplish the task.
 *
 * Method 1: control by compilation flags.
 * That is, the log library defines a set of compilation flags to control
 * the behaviors of the log macros.
 *
 * This method is coarse, and affects the behaviors of *all* log macros.
 * It also requires re-complication of the whole program.
 *
 * Method 2: disconnect from the log sources.
 * That is, the users do not make a connection to the log source.
 * The method exploits the event model, and the log records are not received.
 *
 * Method 3: filter the log records.
 * That is, the users connect the log source to a log sink that filters
 * the log records.
 * Log filtering is flexible, but involes more overhead.
 *
 * However, the above two methods are not efficient, since the log records
 * have already been created.
 * This is a kind of nonsense logging.
 * The creation of a log record can be expensive.
 * The log filtering adds even more overhead.
 *
 * The event model alone does not give any hint about the users' intentions,
 * In order to prevent nonsense logging and avoid performance degradation,
 * the log model has to be extended beyond the event model.
 *
 * Method 4: improve configurability, to a certain extent.
 *
 * However, configurability itself is a big topic, and can easily grow beyond
 * the scope of logging.
 * The log library is never intended to provide a complete system of
 * configuration.
 *
 * ### A solution
 *
 * A system/subsystem consists of several components, and components may be
 * combined/aggregated into other components.
 * One use case is to enable/disable logging from the outermost component.
 * Such intention must be propagated from the outermost to the innermost
 * components, and ultimately reach the log sites.
 *
 * Method 5: check the existence of terminal log sinks.
 * That is, if an intermediate logger has no terminal log sinks at its
 * downstream, then there is no need to create or commit any log records
 * to the logger.
 *
 * A simple method is to let an intermediate logger adopt the **passive
 * connection** stragety.
 *
 * * An intermediate logger **shall not** connect to combined/aggregated upstream
 *   log sources initially.
 *   It is *disabled* by default.
 *
 * * When the first log sink is connected to the intermediate logger,
 *   the logger connects to the combined/aggregated upstream log sources.
 *   It becomes *enabled*.
 *
 * * When the last log sink is disconnected from the intermediate logger,
 *   the logger disconnects from the combined/aggregated upstream log sources.
 *   It becomes *disabled*.
 *
 * * A terminal log sink can be *enabled* by default.
 *
 * * The chain of connections is driven by the terminal log sinks.
 *   The granularity is a little coarse that logging is enabled/disabled
 *   for a component as a whole.
 *   i.e., all of its combined/aggregated components are configured together.
 *
 * This method has the following features.
 *
 * * Runtime configuration.
 *   The configuration is performed at runtime, instead of compile time.
 *
 * * Dynamic configuration.
 *   The configuration can be changed dynamically.
 *   It is not a one-time configuration at start up.
 *
 * * Self-driven configuration.
 *   The configuration is done by the logging facility itself.
 *   It is independent of external configuration systems.
 *
 * * On-demand configuration.
 *   The creation of log records is on-demand, by users' intentions.
 *
 * ### Interface extention
 *
 * To support more features without adding too much weight to the base
 * framework of logging, the log library provides the `ILogEventSinkEx`
 * interface as an extention of `ILogEventSink`.
 * The `ILogEventSinkEx` interface provides more methods to offer extra
 * features.
 *
 * The `ILogEventSinkEx` interface provides `RegisterSource()`,
 * `UnregisterAllSources()` and `IsEnabled()` methods for using the passive
 * connection stragety.
 *
 * The component that uses the logger shall call `RegisterSource()` to specify
 * the upstream log sources.
 * When the first log sink is connected, the logger shall connect to
 * all upstream log sources, and become enabled.
 * When the last log sink is disconnected, the logger shall disconnect to
 * all upstream log sources, and become disabled.
 *
 * When the component is disposed, it **shall** call the logger's
 * `UnregisterAllSources()` method to release the reference counts for
 * the upstream log sources to avoid circular references.
 *
 * The log macros accepts both `ILogEventSink` and `ILogEventSinkEx`.
 * If `Ptr<ILogEventSinkEx>` or `ILogEventSinkEx*` is passed to the log macros,
 * the log macros will respect the state of the logger by calling `IsEnabled()`,
 * before the creation of log records.
 *
 * ## Pending log values
 *
 * It could be painful for users to provide common information at every log
 * site.
 * It is desired that common information can be added to log records
 * automatically.
 *
 * Since log sinks are processers of log records, the task of augmenting
 * log records with common log values shall be done by log sinks.
 *
 * The `ILogEventSinkEx` provides the `AddValue()` method to add pending log values.
 * The pending log values can be removed via `RemoveValue()`.
 *
 * Pending log values can be **high-order** log values.
 * A high-order log value is a log value that generates a log value.
 * If a pending log value is high-order, the logger will add the generated
 * log value to the log records.
 *
 * ## Log filter
 *
 * A log filter examines the named values in a log record, and makes a decision
 * whether the log record should be discarded.
 *
 * A filter implements `ILogFilter` interface.
 * Users can use the `CreateLogFilter()` function template to create
 * functor-based log filters.
 *
 * ## Logger
 *
 * The log library provides the `Logger` component class as an intermediate
 * logger.
 * The CID is `"edu.uestc.nsfx.Logger"`.
 * The component provides `ILogEvent` and `ILogEventSinkEx`.
 *
 * The `Logger` **does not** make **deep** copies of log records.
 *
 * ## Log formatter
 *
 * Log records are created to be examined.
 * In many cases, the examination is performed by human users who generally
 * want to examine the log records in a human-readible form.
 * Since a log record can carry arbitrary log values, the users are responsible
 * to determine how a log record is formatted.
 *
 * The log library provides the `ILogFormatter` interface.
 * The interface outputs log records to an output stream.
 * Users can use the `CreateLogFilter()` function template to create functor-based
 * log formatter.
 *
 * ## Stream sink
 *
 * The log library provides the `ILogStreamSink` interface.
 * The interface supports pending log values and log filters.
 * Besides, it also provides two methods `AddStream()` and `AddFile()`.
 * It does not passive connection though.
 *
 * The library provides the `LogStreamSink` component class as a terminal log
 * sink.
 * The CID is `"edu.uestc.nsfx.LogStreamSink"`.
 * The component provides `ILogStreamSink`, and takes the responsibility to
 * create files and manage streams.
 * It uses/requires `ILogFormatter` to work.
 *
 * The `LogStreamSink` **does not** make **deep** copies of log records.
 *
 */


#endif // CONFIG_H__A5BE74BF_215D_493B_8BB1_8F90D9316F15

